﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace NeuroSpeech.XamlTypeResolver
{
    public class XTAssembly
    {

        public Assembly Assembly { get; private set; }

        public bool HasXamlNamespace { get; set; }

        public XTAssembly(Assembly asm)
        {
            Assembly = asm;

            Load();
        }

        #region private void Load(bool loadAll)
        private void Load()
        {

            LoadNamespaces();
            List<Type> types = new List<Type>(Assembly.GetTypes());

            if (HasXamlNamespace)
            {
                foreach (Type item in types)
                {
                    if (!IsXamlInitializationSupported(item))
                        continue;

                    string ns = item.Namespace;

                    XTNamespaceDef def = namespaceList.FirstOrDefault(x => x.ClrNamespace == ns);
                    if (def != null) {
                        XTNamespace ns2 = XTNamespace.GetNamespace(null,def.Namespace,null,def.Prefix);
                        ns2.TypeList.Add(new XTType(item));
                    }

                }
            }
            else 
            {
                foreach (Type item in types)
                {
                    string ns = item.Namespace;
                    if (string.IsNullOrWhiteSpace(ns))
                        continue;

                    if (!IsXamlInitializationSupported(item))
                        continue;



                    XTNamespace ns2 = XTNamespace.GetNamespace(Assembly, null, item.Namespace,"");
                    ns2.TypeList.Add(new XTType(item));

                    if (item.FullName == "System.Object")
                    {
                        ns2.Prefix = "sys";
                    }
                }
            }

        }

        private bool IsXamlInitializationSupported(Type item) {
            if (!item.IsClass)
                return false;

            if (!item.GetConstructors().Any(x => x.GetParameters().Length == 0))
                return false;

            if (item.IsArray)
                return false;

            if (item.IsNested)
                return false;

            if (IsBaseType(item, "System.Windows.Markup.MarkupExtension"))
                return false;

            if (item.Name.Contains('<') || item.Name.Contains('>'))
                return false;

            return true;
        }

        #region private bool IsBaseType(Type item,Type type)
        private bool IsBaseType(Type item, string baseTypeName)
        {
            if (item.BaseType == null)
                return false;
            if (item.BaseType.FullName == "System.Object")
                return false;
            if (item.BaseType.FullName == baseTypeName)
                return true;
            return IsBaseType(item.BaseType, baseTypeName);
        }
        #endregion


        List<XTNamespaceDef> namespaceList = new List<XTNamespaceDef>();

        private void LoadNamespaces()
        {
            object[] attrs = Assembly.GetCustomAttributes(false);


            foreach (dynamic attr in attrs)
            {
                if (attr.GetType().FullName == "System.Windows.Markup.XmlnsDefinitionAttribute")
                {
                    XTNamespaceDef def = new XTNamespaceDef
                    {
                        Namespace = attr.XmlNamespace,
                        ClrNamespace = attr.ClrNamespace
                    };
                    namespaceList.Add(def);
                }
            }

            foreach (dynamic attr in attrs)
            {
                if (attr.GetType().FullName == "System.Windows.Markup.XmlnsPrefixAttribute")
                {
                    string ns = attr.XmlNamespace;
                    XTNamespaceDef def = namespaceList.FirstOrDefault(x => x.Namespace == ns);
                    if (def != null)
                    {
                        def.Prefix = attr.Prefix;
                    }
                }
            }

            HasXamlNamespace = namespaceList.Count > 0;

        }


        #endregion

    }
}
